package com.alibaba.citrus.cr.mn.order.center.common.util;

import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.util.DateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.tuple.Pair;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author zhangxiaorui
 * @ClassName AssertUtils
 * @description: TODO
 * @date 2023/04/20 20:47
 * @version: 1.0
 */
public class AssertUtils {
    /**
     * 数字校验（正整数）
     */
    private static final String NUMBER_REG_INTEGER = "(^[1-9]\\d*$)";

    /**
     * 数字校验（正整数包含零）
     */
    private static final String NUMBER_REG_POSITIVE = "(^[0-9]\\d*$)";

    /**
     * 数字校验（整数 or 小数）
     */
    private static final String NUMBER_REG = "^\\d+(\\.\\d{1,})$|(^[1-9]\\d*$)";

    /**
     * 金额校验，只允许两位小数
     */
    private static final String MONEY_REG = "^\\d+(\\.\\d{1,2})$|(^[1-9]\\d*$)";

    public static final String TYPE_DATE = "DATE";
    public static final String TYPE_TIME = "TIME";
    public static final String START_TIME = "START_TIME";
    public static final String END_TIME = "END_TIME";

    public static void isTrue(boolean success, String errorCode, Object... args) {
        if (success) {
            throw new FunctionException(errorCode, args);
        }
    }

    public static void isTrue(boolean success, String errorCode) {
        if (success) {
            throw new FunctionException(errorCode);
        }
    }

    public static void checkRequired(boolean o1Success, boolean o2Success, String errorCode) {
        if (o1Success || o2Success) {
            throw new FunctionException(errorCode);
        }
    }

    public static void checkRequired(Pair<String, String> pair, String errorCode, Object... args) {
        boolean lBlank = StringUtils.isBlank(pair.getLeft());
        boolean rBlank = StringUtils.isBlank(pair.getRight());
        if (lBlank || rBlank) {
            throw new FunctionException(errorCode, args);
        }
    }

    /**
     * 校验：允许两个值成对存在 或 成对不存在
     *
     * @param pair
     * @param errorCode
     */
    public static void checkNotRequired(Pair<String, String> pair, String errorCode, String errorMessage) {
        String left = pair.getLeft();
        String right = pair.getRight();
        // 若都为空 or 都不空，则返回成功
        if ((StringUtils.isBlank(left) && StringUtils.isBlank(right))
                || StringUtils.isNotBlank(left) && StringUtils.isNotBlank(right)) {
            return;
        }
        // 其中一个空，一个不空则报错
        throw new FunctionException(errorCode, errorMessage);
    }

    /**
     * 校验参数 全空或者全不空
     *
     * @param errorCode
     * @param errorMessage
     * @param params
     * @return
     */
    public static void checkNotRequired(String errorCode, String errorMessage, String... params) {
        // 判断全部为空
        boolean allEmpty = Arrays.stream(params).allMatch(StringUtils::isBlank);
        boolean allNotEmpty = Arrays.stream(params).allMatch(StringUtils::isNotBlank);
        if (allEmpty || allNotEmpty) {
            return;
        }
        throw new FunctionException(errorCode, errorMessage);
    }

    /**
     * 校验：长度校验，校验必填字段长度
     *
     * @param param
     * @param maxLen
     * @param errorCode
     * @param errorMessage
     */
    public static void lengthCheck(String param, Integer maxLen, String errorCode, String errorMessage) {
        lengthCheck(param, maxLen, true, errorCode, errorMessage);
    }

    /**
     * 校验：长度校验，校验必填字段长度
     *
     * @param param
     * @param maxLen
     * @param required     可选择 当前字段是否必填字段；若非必填字段，可允许为空，跳过，不进行长度校验
     * @param errorCode
     * @param errorMessage
     */
    public static void lengthCheck(String param, Integer maxLen, Boolean required, String errorCode, String errorMessage) {
        if (Objects.isNull(maxLen)) {
            maxLen = 0;
        }
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        // 校验最长长度，长度0校验基本命中不到
        int length = StringUtils.length(param);
        if (length > maxLen || length == 0) {
            throw new FunctionException(errorCode, errorMessage, String.valueOf(length), maxLen.toString());
        }
    }

    /**
     * 校验：金额参数不允许为 0 跟 负数
     *
     * @param param
     * @param required
     * @param errorCode
     * @param errorMessage
     */
    public static void moneyCheck(String param, Boolean required, String errorCode, String errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        // 金额参数不允许为零或负数
        if (BigDecimal.ZERO.compareTo(new BigDecimal(param)) >= 0) {
            throw new FunctionException(errorCode, errorMessage);
        }
        // 金额参数 最多2位小数
        if (!Pattern.compile(MONEY_REG).matcher(param).matches()) {
            throw new FunctionException(errorCode, errorMessage);
        }
    }

    /**
     * 校验是否是 数字类型，整数or小数
     *
     * @param param
     * @param required
     * @param errorCode
     * @param errorMessage
     */
    public static void isNumber(String param, Boolean required, String errorCode, String errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        if (!StringUtils.isNumeric(param) && !Pattern.compile(NUMBER_REG).matcher(param).matches()) {
            throw new FunctionException(errorCode, errorMessage);
        }
    }

    /**
     * 校验是否是数字类型 包括整数，小数
     *
     * @param param
     * @param required
     * @param errorCode
     * @param errorMessage
     */
    public static void isAmountNumber(String param, Boolean required, String errorCode, String errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        if (!NumberUtils.isCreatable(param) && !Pattern.compile(NUMBER_REG).matcher(param).matches()) {
            throw new FunctionException(errorCode, errorMessage);
        }
    }

    /**
     * 校验是否是 数字类型，正整数
     */
    public static void isWholeNumber(String param, Boolean required, String errorCode, String... errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        if (!StringUtils.isNumeric(param) && !Pattern.compile(NUMBER_REG_INTEGER).matcher(param).matches()) {
            throw new FunctionException(errorCode, errorMessage);
        }
    }

    /**
     * 校验是否是 数字类型，整数
     */
    public static void isWholePositiveNumber(String param, Boolean required, String errorCode, String... errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        if (!StringUtils.isNumeric(param) && !Pattern.compile(NUMBER_REG_POSITIVE).matcher(param).matches()) {
            throw new FunctionException(errorCode, errorMessage);
        }
    }

    /**
     * 校验：日期校验，校验日期格式
     * 根据 param.length + pattern = yyyy-MM-dd \ yyyy-MM-dd HH:mm:ss
     *
     * @param param
     * @param maxLen
     * @param required     可选择 当前字段是否必填字段；若非必填字段，可允许为空，跳过，不进行校验
     * @param pattern
     * @param errorMessage
     */
    public static void isDateOrTime(String param, Integer maxLen, Boolean required, String pattern, String errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        // 校验最长长度
        int length = StringUtils.length(param);
        if (length > maxLen) {
            throw new FunctionException("OC-01-001-01-15-004", errorMessage, String.valueOf(length), maxLen.toString());
        }
        if (length < maxLen) {
            throw new FunctionException("OC-01-001-01-15-013", errorMessage, pattern);
        }
        // 校验格式
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            sdf.parse(param);
        } catch (ParseException e) {
            throw new FunctionException("OC-01-001-01-15-013", errorMessage, pattern);
        }
    }

    public static Map<String, String> timeFormatCheck(String startTime, String endTime, String startErrMsg, String endErrMsg, String type) {
        Map<String, String> timeMap = new HashMap<>(2);
        Date startDate = timeFormatCheck(startTime, startErrMsg, type, Boolean.TRUE);
        Date endDate = timeFormatCheck(endTime, endErrMsg, type, Boolean.FALSE);
        if (startDate != null && endDate != null) {
            AssertUtils.isTrue(startDate.after(endDate), "OC-01-001-01-15-012", startErrMsg, endErrMsg);
        }
        timeMap.put(START_TIME, DateUtils.toDateStr(startDate, DateUtils.DATETIME_FORMAT));
        timeMap.put(END_TIME, DateUtils.toDateStr(endDate, DateUtils.DATETIME_FORMAT));
        return timeMap;
    }

    private static Date timeFormatCheck(String time, String errMsg, String type, boolean isBegin) {
        if (org.apache.commons.lang.StringUtils.isBlank(time)) {
            return null;
        }
        Date date = null;
        String format = "";
        if (TYPE_DATE.equals(type)) {
            AssertUtils.isDateOrTime(time, 10,false, DateUtils.PATTEN_YMD, errMsg);
            date = DateUtils.getBeginOrEndByStr(time, isBegin);
            format = DateUtils.PATTEN_YMD;
        } else if (TYPE_TIME.equals(type)) {
            AssertUtils.isDateOrTime(time, 19,false, DateUtils.DATETIME_FORMAT, errMsg);
            date = DateUtils.string2Date(time, DateUtils.DATETIME_FORMAT);
            format = DateUtils.DATETIME_FORMAT;
        }
        // 传入的时间不为空，但格式化后为空， 说明时间格式化失败 报错出去
        AssertUtils.isTrue(org.apache.commons.lang.StringUtils.isNotBlank(time) && date == null, "OC-01-001-01-15-013", errMsg, format);
        return date;
    }

    /**
     * 校验是否是 Boolean类型
     */
    public static void isBoolean(String param, Boolean required, String errorMessage) {
        // 若字段非必填、可允许为空，跳过长度校验
        if (BooleanUtils.isFalse(required) && StringUtils.isBlank(param)) {
            return;
        }
        if (!("true".equalsIgnoreCase(param) || "false".equalsIgnoreCase(param))) {
            throw new FunctionException("OC-01-001-01-15-006", errorMessage);
        }
    }

    /**
     *  校验list及list内元素长度
     * @param paramList list
     * @param errListMsg list错误信息
     * @param errParamMsg list内元素错误信息
     * @param listSize 需校验的list长度
     * @param paramLength 需校验的元素长度
     */
    public static void lengthCheckList(List<String> paramList, String errListMsg, String errParamMsg, Integer listSize, Integer paramLength) {
        if (CollectionUtils.isEmpty(paramList)) {
            return;
        }
        AssertUtils.isTrue(paramList.size() > listSize, "OC-01-001-01-15-004", errListMsg, paramList.size(), listSize.toString());
        paramList.forEach(param -> {
            AssertUtils.lengthCheck(param, paramLength, false, "OC-01-001-01-15-004", errParamMsg);
        });
    }
}
